package com.xhwl.data.controller;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.vdurmont.emoji.EmojiParser;
import com.xhwl.common.constant.cent.message.MessageConstant;
import com.xhwl.common.dto.cent.sdata.AccountDTO;
import com.xhwl.common.dto.cent.sdata.AccountDetailDTO;
import com.xhwl.common.dto.cent.sdata.AccountPersonalDTO;
import com.xhwl.common.enums.CodeEnum;
import com.xhwl.common.enums.PasswordEditEnum;
import com.xhwl.common.enums.ThirdAccountTypeEnum;
import com.xhwl.common.exception.BusinessException;
import com.xhwl.common.exception.DataException;
import com.xhwl.common.pojo.Config;
import com.xhwl.common.pojo.ResultJson;
import com.xhwl.common.pojo.cent.sdata.*;
import com.xhwl.common.pojo.cent.sdata.devplatform.Developer;
import com.xhwl.common.pojo.cent.sdata.personnel.Staff;
import com.xhwl.common.pojo.cent.sdata.personnel.StaffOrganization;
import com.xhwl.common.utils.CentDataVerifyUtil;
import com.xhwl.common.utils.DataVerifyUtil;
import com.xhwl.common.utils.DateUtils;
import com.xhwl.data.service.*;
import com.xhwl.data.service.personal.IStaffOrganizationService;
import com.xhwl.data.service.personal.IStaffService;
import com.xhwl.data.util.Constant;
import com.xhwl.data.util.RedisUtils;
import com.xhwl.starter.config.IConfig;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;


/**
 * @Author: JCccc
 * @Description:
 * @Date: Create in 14:28 2021/1/21
 */
@RestController
public class PersonalController {
    private static final Logger log = LoggerFactory.getLogger(PersonalController.class);

    @Autowired
    IEnterpriseService enterpriseService;
    @Autowired
    IProjectService projectService;
    @Autowired
    IAccountService accountService;
    @Autowired
    IMessageCodeService messageCodeService;
    @Autowired
    IAccountOpenAuthService accountOpenAuthService;

    @Autowired
    IEnterpriseConfigService enterpriseConfigService;
    @Autowired
    IStaffOrganizationService staffOrganizationService;

    @Autowired
    private IConfig config;
    @Autowired
    RedisUtils redisUtils;
    private static final String CONFIG_CODE = "QR_CODE_URL";

    @Autowired
    IAppService appService;

    @Autowired
    private IStaffService staffService;

    /**
     * 获取个人中心 账号信息
     *
     * @param operateAccount
     * @return
     */
    @GetMapping(value = "/personal/get")
    public ResultJson get(@RequestHeader(value = "appId", required = true) String appId,
                          @RequestHeader(value = "clientType", required = false) Integer clientType,
                          @RequestHeader(value = "industryId", required = true) Short industryId,
                          Account operateAccount) {
        if (null == operateAccount) {
            return ResultJson.fail("获取登录信息失败");
        }
        Integer accountId = operateAccount.getId();
        String entName = "";
        String roleName = "";
        String proName = "";
        String roleCode = "";
        List<Integer> entIds = new ArrayList<>();
        List<Integer> roleIds = new ArrayList<>();
        List<Integer> proIds = new ArrayList<>();
        List<Integer> orgIds = new ArrayList<>();
        List<Enterprise> enterpriseList = enterpriseService.list(null, operateAccount);
        List<AccountDetailDTO> roleInfoList = accountService.getAccountRoleInfoByIdList(Collections.singletonList(accountId), null);
        List<AccountDetailDTO> projectInfoList = accountService.getAccountProjectInfoByIdList(Collections.singletonList(accountId));
        QueryWrapper<StaffOrganization> staffOrganizationQueryWrapper = new QueryWrapper<>();
        staffOrganizationQueryWrapper.eq("account_id", operateAccount.getId());
        List<StaffOrganization> staffOrganizations = staffOrganizationService.list(staffOrganizationQueryWrapper);
        if (!CollectionUtils.isEmpty(enterpriseList)) {
            List<String> entNameList = enterpriseList.stream().map(Enterprise::getName).collect(Collectors.toList());
            //拼接企业名称，以‘、’ 号拼接
            entName = String.join("、", entNameList);
            entIds = enterpriseList.stream().map(Enterprise::getId).collect(Collectors.toList());
        }
        if (!CollectionUtils.isEmpty(roleInfoList)) {
            List<String> roleNameList = roleInfoList.stream().map(AccountDetailDTO::getRoleName).collect(Collectors.toList());
            List<String> roleCodeList = roleInfoList.stream().map(AccountDetailDTO::getRoleCode).collect(Collectors.toList());
            roleCodeList.removeAll(Collections.singleton(null));
            //拼接角色名称，以‘、’ 号拼接
            roleName = String.join("、", roleNameList);
            roleIds = roleInfoList.stream().map(AccountDetailDTO::getRoleId).collect(Collectors.toList());
            roleCode = String.join("、",roleCodeList);
        }
        if (!CollectionUtils.isEmpty(projectInfoList)) {
            List<String> projectNameList = projectInfoList.stream().map(AccountDetailDTO::getProjectName).collect(Collectors.toList());
            //拼接角色名称，以‘、’ 号拼接
            proName = String.join("、", projectNameList);
            proIds = projectInfoList.stream().map(AccountDetailDTO::getProjectId).collect(Collectors.toList());
        }
        if (!CollectionUtils.isEmpty(staffOrganizations)){
            orgIds = staffOrganizations.stream().map(StaffOrganization::getOrgId).collect(Collectors.toList());
        }
        boolean bindWeChat = false;
        AccountOpenAuth bindWeChatInfo = accountOpenAuthService.getOne(new AccountOpenAuth().setAccountId(operateAccount.getId()).setType(ThirdAccountTypeEnum.WE_CHAT.getType()).setAppId(appId));
        if (Objects.nonNull(bindWeChatInfo)) {
            bindWeChat = true;
        }
        //第三方绑定头像
        String openHeadImg = "";
        List<AccountOpenAuth> accountOpenAuths = accountOpenAuthService.listBindOpen(operateAccount.getId(), appId);
        if (!CollectionUtils.isEmpty(accountOpenAuths)) {
            for (AccountOpenAuth accountOpenAuth : accountOpenAuths) {
                if (StringUtils.isNotEmpty(accountOpenAuth.getHeadImg())) {
                    openHeadImg = accountOpenAuth.getHeadImg();
                    break;
                }
            }
        }
        Account accountInfo = accountService.findById(accountId);
        if (null != accountInfo.getName()) {
            String nameEmoji = EmojiParser.parseToUnicode(accountInfo.getName());
            accountInfo.setName(nameEmoji);
        }
        if (null != accountInfo.getNickname()) {
            String nicknameEmoji = EmojiParser.parseToUnicode(accountInfo.getNickname());
            accountInfo.setNickname(nicknameEmoji);
        }
        AccountDTO accountDTO = new AccountDTO();
        BeanUtils.copyProperties(accountInfo, accountDTO);
        accountDTO.setBindWeChat(bindWeChat)
                .setPassword("*******")
                .setEnterpriseName(entName)
                .setEnterpriseIds(entIds)
                .setProjectName(proName)
                .setProjectIds(proIds)
                .setRoleName(roleName)
                .setRoleIds(roleIds)
                .setRoleCode(roleCode)
                .setOpenHeadImg(openHeadImg)
                .setOrgIds(orgIds);
//        PersonalAccountVO personalAccountVO=new PersonalAccountVO();
//        BeanUtils.copyProperties(accountInfo, personalAccountVO);
//        personalAccountVO.setBindWeChat(bindWeChat)
//                .setEnterpriseName(entName)
//                .setProjectName(proName)
//                .setRoleName(roleName);
        //将用户退出时的企业放在企业集合的第一个位置-作为下次登录的默认企业
        Integer defaultEnterprise = accountDTO.getDefaultEnterprise();
        accountDTO.setEnterpriseId(defaultEnterprise);
        List<Integer> enterpriseIds = accountDTO.getEnterpriseIds();
        // 找到退出时的企业Id在集合中的位置
        int index = enterpriseIds.indexOf(defaultEnterprise);
        if (index != -1) {
            // 移除该数字
            enterpriseIds.remove(index);
            // 插入数字到第一个位置
            enterpriseIds.add(0, defaultEnterprise);
        } else {
            log.warn("用户已离职上次退出时的企业");
        }
        accountDTO.setEnterpriseIds(enterpriseIds);
        return ResultJson.success(accountDTO);
    }


    /**
     * 修改个人中心的 账号信息
     *
     * @param operateAccount
     * @param accountDTO
     * @return
     */
    @PostMapping(value = "/personal/update")
    public ResultJson update(@RequestHeader(value = "appId", required = true) String appId,
                             @RequestHeader(value = "clientType", required = false) Integer clientType,
                             @RequestHeader(value = "industryId", required = true) Short industryId,
                             Account operateAccount, @RequestBody AccountDTO accountDTO) {
        operateAccount.setIndustryId(industryId);
        Account account = new Account();
        account.setId(operateAccount.getId());
        //需要修改名字
        if (StringUtils.isNotEmpty(accountDTO.getName())) {
            //姓名校验
            //不允许 空格串和空数据
            if (DataVerifyUtil.isSpaceString(accountDTO.getName())) {
                return ResultJson.fail("姓名不能为空");
            }
            //不允许 除中文、英文大小写外
//            if (!DataVerifyUtil.isChineseEnglish(accountDTO.getName())) {
//                return ResultJson.fail("姓名只允许输入中文、英文大小写");
//            }
            //只允许输入15个以内的字符
            if (!DataVerifyUtil.isInRangeString(1, 20, accountDTO.getName())) {
                return ResultJson.fail("姓名只允许输入20个以内的字符");
            }
            account.setName(accountDTO.getName());
        }
        //需要修改邮箱
        if (null != accountDTO.getEmail()) {
            if (!"".equals(accountDTO.getEmail())) {
                if (!DataVerifyUtil.isEmail(accountDTO.getEmail())) {
                    return ResultJson.fail("邮箱格式不正确");
                }
                if (!DataVerifyUtil.isInRangeString(1, 255, accountDTO.getEmail())) {
                    return ResultJson.fail("邮箱只允许输入255个以内的字符");
                }
            }
            account.setEmail(accountDTO.getEmail());
        }
        if (null != accountDTO.getSex()) {
            account.setSex(accountDTO.getSex());
        }
        if (null != accountDTO.getNickname()) {
            account.setNickname(accountDTO.getNickname());
        }
        if (null != accountDTO.getAge()) {
            account.setAge(accountDTO.getAge());
        }
        if (null != accountDTO.getHeadImg()) {
            account.setHeadImg(accountDTO.getHeadImg());
        }
        //手机号也是允许修改的，但是 根据业务特殊处理，额外的接口
        ResultJson resultJson = null;
        try {
            //修改个人中心信息
            resultJson = accountService.modifyPersonalInfo(account);
        } catch (Exception e) {
            return ResultJson.fail(e.getMessage());
        }
        return resultJson;
    }


    /**
     * 短信验证码发送接口 - 模拟
     *
     * @param phone
     * @return
     */
    @GetMapping("/personal/send-msg-code")
    public ResultJson sendMsgCode(Account operateAccount,
                                  @RequestHeader(value = "appId", required = true) String appId,
                                  @RequestHeader(value = "clientType", required = false) Integer clientType,
                                  @RequestHeader(value = "industryId", required = true) Short industryId,
                                  @RequestParam("phone") String phone,
                                  @RequestParam(value = "projectId", required = false) Integer projectId) {
        operateAccount.setIndustryId(industryId);
        return messageCodeService.sendMsgCode(phone, projectId, operateAccount);
    }

    /**
     * 修改手机号
     *
     * @param
     * @param
     * @return
     */
    @PostMapping("/personal/phone-edit-verify")
    public ResultJson phoneEdit(
            Account operateAccount,
            @RequestHeader(value = "appId", required = true) String appId,
            @RequestHeader(value = "clientType", required = false) Integer clientType,
            @RequestHeader(value = "industryId", required = true) Short industryId,
            @RequestBody AccountPersonalDTO accountPersonalDTO, Developer developer) {
        operateAccount.setIndustryId(industryId);
        operateAccount.setDevelopId(developer.getId());
        return accountService.phoneEdit(operateAccount, accountPersonalDTO);
    }


    /**
     * 修改密码 -个人中心
     *
     * @param operateAccount
     * @param accountPersonalDTO
     * @return
     */
    @PostMapping(value = "/personal/pwd-edit")
    public ResultJson pwdEdit(Account operateAccount,
                              @RequestHeader(value = "appId", required = true) String appId,
                              @RequestHeader(value = "clientType", required = false) Integer clientType,
                              @RequestHeader(value = "industryId", required = true) Short industryId,
                              @RequestBody AccountPersonalDTO accountPersonalDTO) {
        operateAccount.setIndustryId(industryId);
        //验证通过，修改密码
        String newPwd = accountPersonalDTO.getNewPwd();
        if (null == accountPersonalDTO.getVerifyType()) {
            return ResultJson.fail("参数异常");
        }
        Account accountDb = accountService.findById(operateAccount.getId());
        Integer verifyType = accountPersonalDTO.getVerifyType();
        ResultJson resultJson = null;
        PasswordEditEnum passwordEditEnum = PasswordEditEnum.getPasswordEditEnum(verifyType);
        if (PasswordEditEnum.PWD_VERIFY.equals(passwordEditEnum)) {

            //检测是否已经触发账户密码修改锁定，如果触发，不能进行校验
            if (null != redisUtils.get(industryId + "_" + Constant.PWD_EDIT_ERROR_LOCKING + operateAccount.getId())) {
                deleteAuthentication(operateAccount.getId(), appId);
                return ResultJson.fail(CodeEnum.LOGIN_PWD_LOCKING.getCode(), "旧密码多次输入错误，请于10分钟后再尝试");
            }
            //旧密码
            String pwd = Optional.ofNullable(accountPersonalDTO.getPwd()).orElseThrow(() -> new DataException("密码不能为空"));
            ResultJson verifyPwd = accountService.verifyPwd(operateAccount.getId(), pwd);
            if (CodeEnum.SUCCESS.code != verifyPwd.getCode()) {
                int errorCount = 1;
                long secondsToBeforeDawn = DateUtils.getSecondsToBeforeDawn();
                if (null == redisUtils.get(industryId + "_" + Constant.PWD_EDIT_ERROR_COUNT + operateAccount.getId())) {
                    //设置当前自然日内错误次数 为 1
                    redisUtils.setWithSeconds(industryId + "_" + Constant.PWD_EDIT_ERROR_COUNT + operateAccount.getId(), errorCount, secondsToBeforeDawn);
                } else {
                    //设置当前自然日内错误次数自增
                    redisUtils.increment(industryId + "_" + Constant.PWD_EDIT_ERROR_COUNT + operateAccount.getId());
                }
                errorCount = (Integer) redisUtils.get(industryId + "_" + Constant.PWD_EDIT_ERROR_COUNT + operateAccount.getId());
                //区分场景提示语，到达5次，触发账户锁定；不达5次，返回常规错误校验提示
                if (Constant.PWD_EDIT_ERROR_LIMIT_NUMBER_TIMES <= errorCount) {
                    //触发账号锁定触发
                    redisUtils.setWithMinute(industryId + "_" + Constant.PWD_EDIT_ERROR_LOCKING + operateAccount.getId(), operateAccount.getId(), Constant.PWD_EDIT_ERROR_LOCKING_NUMBER_TIMES);
                    deleteAuthentication(operateAccount.getId(), appId);
                    return ResultJson.fail(CodeEnum.LOGIN_PWD_LOCKING.getCode(), "旧密码多次输入错误，请于10分钟后再尝试");
                }

                return ResultJson.fail("旧密码校验不通过");
            }
        } else if (PasswordEditEnum.PHONE_VERIFY.equals(passwordEditEnum)) {
            String phone = Optional.ofNullable(accountPersonalDTO.getPhone()).orElseThrow(() -> new DataException("手机号不能为空"));
            //手机号格式校验
            CentDataVerifyUtil.phoneVerify(phone);
            String bindPhone = accountDb.getPhone();
            if (StringUtils.isEmpty(bindPhone)) {
                throw new BusinessException("当前账号未关联手机号信息");
            }
            if (!phone.equals(bindPhone)) {
                log.info("当前传入的手机号与该账号绑定的手机号不一致,传入的phone={},绑定的手机={}", phone, bindPhone);
                throw new BusinessException("手机号信息有误,请确认手机号与该账号已关联绑定");
            }
            String msgCode = Optional.ofNullable(accountPersonalDTO.getMsgCode()).orElseThrow(() -> new DataException("短信验证码不能为空"));
            //短信验证码校验
            resultJson = messageCodeService.phoneMsgCodeVerify(String.valueOf(industryId), phone, msgCode, true);
            if (!CodeEnum.SUCCESS.getCode().equals(resultJson.getCode())) {
                return resultJson;
            }
        } else {
            throw new DataException("验证类型不支持");
        }
        resultJson = accountService.modifyPwd(operateAccount.getId(), newPwd);
        return resultJson;
    }


    /**
     * 删除登录token
     */
    private void deleteAuthentication(Integer userId, String appId) {
        String tokenKey = null;
        try {
            if (Constant.ADMIN_APPID.equals(appId)) {
                tokenKey = Constant.getAdminTokenKey(String.valueOf(userId));
            } else {
                tokenKey = Constant.getTokenKey(appId, String.valueOf(userId));
            }
            redisUtils.remove(tokenKey);
            redisUtils.remove(Constant.getPermissionKey(appId, String.valueOf(userId)));
            redisUtils.remove(Constant.getAccountInfoKey(appId, String.valueOf(userId)));
            App app = appService.getByAppId(appId);
            Integer appType = app.getAppType();
            redisUtils.remove(Constant.getLoginTagKey(appType, String.valueOf(userId)));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public ResultJson errorMsgCodeDeal(Short industryId, String phone, String msgCodeCache) {
        int errorCount = 1;
        Long secondsToBeforeDawn = DateUtils.getSecondsToBeforeDawn();
        if (null == redisUtils.get(industryId + "_" + MessageConstant.MSG_CODE_ERROR_COUNT + phone)) {
            //设置当前自然日内错误次数 为 1
            redisUtils.setWithSeconds(industryId + "_" + MessageConstant.MSG_CODE_ERROR_COUNT + phone, errorCount, secondsToBeforeDawn);
        } else {
            //设置当前自然日内错误次数自增
            redisUtils.increment(industryId + "_" + MessageConstant.MSG_CODE_ERROR_COUNT + phone);
        }

        errorCount = (Integer) redisUtils.get(industryId + "_" + MessageConstant.MSG_CODE_ERROR_COUNT + phone);
        //重新赋值，不改变验证码有效时间
        redisUtils.setWithSeconds(industryId + "_" + MessageConstant.MSG_CODE_PREFIX + phone, msgCodeCache, redisUtils.getExpire(industryId + "_" + MessageConstant.MSG_CODE_PREFIX + phone));
        //区分场景提示语，到达5次，触发账户锁定；不达5次，返回常规错误校验提示
        if (MessageConstant.MSG_CODE_SEND_LOCKING_NUMBER_TIMES <= errorCount) {
            //触发账号锁定触发
            redisUtils.setWithMinute(industryId + "_" + MessageConstant.MSG_CODE_SEND_LOCKING + phone, msgCodeCache, 10);
            return ResultJson.fail(CodeEnum.MSG_CODE_LOCKING);
        }
        return ResultJson.fail(CodeEnum.MSG_CODE_WRONG);
    }


    /**
     * 修改邮箱 （个人中心）
     *
     * @param operateAccount
     * @param accountDTO
     * @return
     */
    @PostMapping(value = "/personal/email-edit")
    public ResultJson emailEdit(Account operateAccount,
                                @RequestHeader(value = "appId", required = true) String appId,
                                @RequestHeader(value = "clientType", required = false) Integer clientType,
                                @RequestHeader(value = "industryId", required = true) Short industryId,
                                @RequestBody AccountDTO accountDTO) {
        return accountService.modifyEmail(industryId, operateAccount.getId(), accountDTO.getEmail());
    }


    /**
     * 修改编辑头像
     *
     * @param appId
     * @param clientType
     * @param industryId
     * @param operateAccount
     * @param accountDTO
     * @return
     */
    @PostMapping(value = "/personal/edit-head-img")
    public ResultJson editHeadImg(@RequestHeader(value = "appId", required = true) String appId,
                                  @RequestHeader(value = "clientType", required = false) Integer clientType,
                                  @RequestHeader(value = "industryId", required = true) Short industryId,
                                  Account operateAccount, @RequestBody AccountDTO accountDTO) {
        Integer operateAccountId = operateAccount.getId();
        return accountService.editHeadImg(operateAccountId, accountDTO.getHeadImg());
    }


    /**
     * 查看电子员工证
     *
     * @param appId
     * @param clientType
     * @param industryId
     * @param operateAccount
     * @return
     */
    @GetMapping(value = "/personal/employee-card-info")
    public ResultJson employeeCardInfo(@RequestHeader(value = "appId", required = true) String appId,
                                       @RequestHeader(value = "clientType", required = false) Integer clientType,
                                       @RequestHeader(value = "industryId", required = true) Short industryId,
                                       @RequestParam("projectId") Integer projectId,
                                       Account operateAccount) {
        Integer operateAccountId = operateAccount.getId();
        String name = operateAccount.getName();
        String phone = operateAccount.getPhone();

        String entName = "";
        String proName = "";
        String roleName = "";
        List<Enterprise> enterpriseList = enterpriseService.list(null, operateAccount);
        List<AccountDetailDTO> roleInfoList = accountService.getAccountRoleInfoByIdList(Collections.singletonList(operateAccountId), null);
        List<AccountDetailDTO> projectInfoList = accountService.getAccountProjectInfoByIdList(Collections.singletonList(operateAccountId));
        if (!CollectionUtils.isEmpty(enterpriseList)) {
            List<String> entNameList = enterpriseList.stream().map(Enterprise::getName).collect(Collectors.toList());
            //拼接企业名称，以‘、’ 号拼接
            entName = String.join("、", entNameList);
        }
        if (!CollectionUtils.isEmpty(roleInfoList)) {
            List<String> roleNameList = roleInfoList.stream().map(AccountDetailDTO::getRoleName).collect(Collectors.toList());
            //拼接角色名称，以‘、’ 号拼接
            roleName = String.join("、", roleNameList);
        }
        if (!CollectionUtils.isEmpty(projectInfoList)) {
            List<String> projectNameList = projectInfoList.stream().map(AccountDetailDTO::getProjectName).collect(Collectors.toList());
            //拼接角色名称，以‘、’ 号拼接
            proName = String.join("、", projectNameList);
        }
        String entLogoUrl = "";
        if (!CollectionUtils.isEmpty(enterpriseList)) {
            Enterprise enterprise = enterpriseList.get(0);
            Integer enterpriseId = enterprise.getId();
            EnterpriseConfig enterpriseConfig = enterpriseConfigService.findByEntId(enterpriseId);
            if (null != enterpriseConfig) {
                entLogoUrl = enterpriseConfig.getLogoUrl();
            }
        }
        String qrCodeUrl = "";
        Config qrCodeConfig = this.config.getProject(CONFIG_CODE, projectId);
        if (null != qrCodeConfig) {
            qrCodeUrl = String.valueOf(qrCodeConfig.getValue());
        }

        //姓名、手机号、所属项目、企业logo、二维码
        EmployeeCardInfo employeeCardInfo = new EmployeeCardInfo();
        employeeCardInfo.setAccountId(operateAccountId);
        employeeCardInfo.setName(name);
        employeeCardInfo.setPhone(phone);
        employeeCardInfo.setEntName(entName);
        employeeCardInfo.setProName(proName);
        employeeCardInfo.setRoleName(roleName);
        employeeCardInfo.setEntLogoUrl(entLogoUrl);
        employeeCardInfo.setQrCodeUrl(qrCodeUrl);
        //添加工号
        QueryWrapper<Staff> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("account_id", operateAccountId);
        Staff staff = staffService.getOne(queryWrapper);
        if (Objects.nonNull(staff)) {
            employeeCardInfo.setWorkCode(staff.getWorkCode());
        }
        return ResultJson.success(employeeCardInfo);
    }


}
